﻿using PivotData;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.Serialization;

namespace PivotIO.XML
{
    /// <summary>
    /// Deal with reading and writing the list of collections
    /// </summary>
    public class CollectionInfoIO
    {
        /// <summary>
        /// Cache collection info
        /// </summary>
        private static Dictionary<int, CollectionInfo> _collectionCache = new Dictionary<int, CollectionInfo>();

        /// <summary>
        /// Set to true when we load up the cache the first time.
        /// </summary>
        private static bool _cacheFilled = false;

        private static Mutex _collectionCacheLock = new Mutex();

        /// <summary>
        /// Reset the cache. Used mostly in testing.
        /// </summary>
        public static void ResetCache()
        {
            _collectionCache = new Dictionary<int, CollectionInfo>();
            _cacheFilled = false;
        }

        /// <summary>
        /// Load the info for a collection. Return null if it isn't there.
        /// </summary>
        /// <param name="collectionId"></param>
        /// <returns></returns>
        public static CollectionInfo LoadCollection(int collectionId)
        {
            lock (_collectionCacheLock)
            {
                LoadAllCollections();
                if (_collectionCache.ContainsKey(collectionId))
                    return _collectionCache[collectionId];
                return null;
            }
        }

        /// <summary>
        /// Return a collection by doing a name lookup
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static CollectionInfo LoadCollection(string name)
        {
            lock (_collectionCacheLock)
            {
                LoadAllCollections();
                return _collectionCache.Where(c => c.Value.Name == name).Select(c => c.Value).FirstOrDefault();
            }
        }

        /// <summary>
        /// Return a list of all loaded collections
        /// </summary>
        /// <returns></returns>
        public static CollectionInfo[] ListAllCollections()
        {
            lock (_collectionCacheLock)
            {
                LoadAllCollections();
                return _collectionCache.Select(c => c.Value).ToArray();
            }
        }

        /// <summary>
        /// Return the max collection iD number.
        /// </summary>
        /// <returns></returns>
        public static int GetMaxCollectionId()
        {
            lock (_collectionCacheLock)
            {
                LoadAllCollections();
                if (_collectionCache.Count == 0)
                    return 0;

                return _collectionCache.Keys.Max();
            }
        }

        /// <summary>
        /// Update or create a collection info.
        /// </summary>
        /// <param name="c"></param>
        public static void SaveCollection(CollectionInfo c)
        {
            lock (_collectionCacheLock)
            {
                LoadAllCollections();
                _collectionCache[c.Id] = c;
                SaveAllCollections();
            }
        }

        /// <summary>
        /// Remove a single collection.
        /// </summary>
        /// <param name="c"></param>
        public static void DeleteCollection(CollectionInfo c)
        {
            lock (_collectionCacheLock)
            {
                LoadAllCollections();
                _collectionCache.Remove(c.Id);
                ImageInfoIO.DeleteAllImages(c.Id);
                SaveAllCollections();
            }
        }

        /// <summary>
        /// Load all collections in from the XML file that was written out.
        /// </summary>
        /// <returns></returns>
        private static void LoadAllCollections()
        {
            // Do we get a cache hit?

            if (_cacheFilled)
                return;

            //
            // If there is no file, return null. Don't create an empty file.
            //

            var fi = new FileInfo(Path.Combine(Utils.GetROOTDataDirectory().FullName, "Collections.xml"));
            if (!fi.Exists)
            {
                _cacheFilled = true;
                return;
            }


            // Change the text into something useful.

            var input = new XmlSerializer(typeof(CollectionInfo[]));
            using (var fs = fi.OpenText())
            {
                var values = input.Deserialize(fs) as CollectionInfo[];
                _collectionCache = values.ToDictionary(c => c.Id);
                _cacheFilled = true;
                return;
            }
        }

        /// <summary>
        /// Save all collections to our specific output file.
        /// </summary>
        /// <param name="collections"></param>
        private static void SaveAllCollections()
        {
            var fi = new FileInfo(Path.Combine(Utils.GetROOTDataDirectory().FullName, "Collections.xml"));

            var output = new XmlSerializer(typeof(CollectionInfo[]));
            using (var fs = fi.CreateText())
            {
                output.Serialize(fs, _collectionCache.Select(c => c.Value).ToArray());
            }
        }

        /// <summary>
        /// Return true if the collection exists, false otherwise.
        /// </summary>
        /// <param name="cId"></param>
        /// <returns></returns>
        /// <remarks>Just look for the directory to exsit</remarks>
        public static bool Exists(int cId)
        {
            return LoadCollection(cId) != null;
        }
    }
}